package gov.child.dao.impl;

import gov.child.dao.AbstractDao;
import gov.child.dao.DepartmentDao;
import gov.child.dao.exception.*;
import gov.child.entities.po.EDepartment;
import gov.child.entities.vo.Page;
import org.hibernate.Session;
import org.hibernate.query.Query;
import org.springframework.stereotype.Repository;

import java.util.*;

/**
 * The type Department dao. --finish
 *
 * @author fzh
 * @since 2017 /9/10
 */
@Repository("departmentDao")
public class DepartmentDaoImpl extends AbstractDao implements DepartmentDao {

    @Override
    public List findAll(Page page) throws EntityQueryException {
        Session session = currentSession();
        Query query;
        String hql = "from EDepartment";
        query = session.createQuery(hql);
        return doPaginate(query, page);
    }

    @Override
    public List findNameAndId() throws EntityQueryException {
        Session session = currentSession();
        // 需要在EDepartment内增加一个这样的构造器
        String hql = "select e.id, e.deptName from EDepartment e";
        List l = session.createQuery(hql).list();
        return parseObjectArrayOfList(l, "id", "name");
    }

    @Override
    public List findNameAndIdByKeyword(String keyword) throws EntityQueryException {
        Session session = currentSession();
        // 需要在EDepartment内增加一个这样的构造器
        String hql = "select e.id, e.deptName from EDepartment e where locate(:keyword, e.deptName) > 0 ";
        List l = session.createQuery(hql).setParameter("keyword", keyword).list();
        return parseObjectArrayOfList(l, "id", "name");
    }

    @Override
    public EDepartment findById(Integer id) throws EntityQueryException {
        Session session = currentSession();
        String hql = "from EDepartment where id = :id";
        return (EDepartment) session.createQuery(hql).setParameter("id", id).uniqueResult();
    }

    @Override
    public List findByDepartmentParentId(Integer id) {
        Session session = currentSession();
        String hql = "from EDepartment where deptParent = :id";
        Query query = session.createQuery(hql).setParameter("id", id);
        return query.list();
    }

    @Override
    public void save(EDepartment department) throws EntitySaveException {
        currentSession().save(department);
    }

    @Override
    public void deleteById(Integer id) throws EntityDeleteException {
        String hql = "delete from EDepartment where id = :id";
        Session session = currentSession();
        if (session.createQuery(hql).setParameter("id", id).executeUpdate() <= 0) throw new EntityDeleteException("department delete failed");
    }

    @Override
    public void update(EDepartment department) throws EntityUpdateException {
        // TODO maybe need optimization
        currentSession().update(department);
    }

    @Override
    public List findParentDepartment() {
        Session session = currentSession();
        String hql = "from EDepartment where deptParent = 0";
        Query query = session.createQuery(hql);
        return query.list();
    }

    @Override
    public Long total() throws PageInitialException {
        Session session = currentSession();
        String hql = "select count(*) from EDepartment";
        Query query = session.createQuery(hql);
        return (Long) query.uniqueResult();
    }

    private List parseObjectArrayOfList(List<Object[]> objects, String... keys) {
        Objects.requireNonNull(objects);
        if (objects.isEmpty()) return Collections.EMPTY_LIST;
        if (!(objects.get(0) instanceof Object[])) throw new RuntimeException("list child must be object array.");
        if (objects.get(0).length != keys.length)
            throw new RuntimeException("first parameter's length must equals the following parameters' length.");
        List<Map> result = new ArrayList<>();
        objects.forEach((Object[] t) -> {
            Map<String, Object> val = new HashMap<>();
            for (int i = 0; i < t.length; i++) {
                val.put(keys[i], t[i]);
            }
            result.add(val);
        });
        return result;
    }
}
